<template>
  <div class="layout-full">
    <div class="d-bar">
      <div class="d-bar-item">
        <span class="d-bar-text">
          {{ this.state.name }}&nbsp;<span class="d-text-small d-text-lightgray">(流程数量：{{ executeList.length }})</span>
        </span>
      </div>
      <div class="d-bar-item d-bar-item-btns">
        <span class="d-form-group-xxs" style="margin-right:8px">
          <input v-model="matchKeyword" class="d-form-input" type="text" placeholder="输入关键字过滤" />
        </span>
        <span v-if="!isView" @click="handleSubmitSave" class="d-bar-text" style="margin-right:8px">
          <button class="d-btn d-btn-primary d-btn-xs" type="button">保存</button>
        </span>
        <span v-if="!isView" @click="handleRunAll" class="d-bar-text" style="margin-right:8px">
          <button class="d-btn d-btn-default d-btn-xs" type="button">预览</button>
        </span>
        <span v-if="isView" @click="handleRunAll" class="d-bar-text" style="margin-right:8px">
          <button class="d-btn d-btn-primary d-btn-xs" type="button">运行</button>
        </span>
        <span v-if="!isView" @click="handleAddNode" class="d-bar-text d-text-linker d-text-lightgray" style="margin-right:8px">
          <PlusRoundIcon title="添加" />
        </span>
        <span v-if="((state.data||{}).config||{}).isCycle || isCycle" class="d-bar-text d-text-linker d-text-lightgray" style="margin-right:8px">
          <FlashLight />
        </span>
        <span @click="handleSettingExe" class="d-bar-text d-text-linker d-text-lightgray" style="margin-right:8px">
          <SettingIcon class="rotate" title="设置" />
        </span>
        <span @click="handleResetAll" class="d-bar-text d-text-linker d-text-lightgray" style="margin-right:8px">
          <ResetIcon title="重置状态" />
        </span>
        <span @click="handleRefresh" class="d-bar-text d-text-linker d-text-lightgray" style="margin-right:8px">
          <RefreshIcon title="刷新" />
        </span>
        <span @click="handleBack"  class="d-bar-text d-text-linker d-text-lightgray">
          <ReturnIcon title="返回" />
        </span>
      </div>
    </div>
    <div class="pages">
      <div v-for="(item, i) in executeList" :key="'item-' + item.id" class="d-paner d-paner-full d-paner-condensed pages-item">
        <div class="d-paner-header">
          <div class="header-content">
            <div class="d-paner-caption">
              <div :title="item.name" class="d-caption-text">{{ item.name }}</div>
            </div>
            <div class="d-bar-tools d-bar-tools-right">
              <span v-if="(item.config||{}).isCycle" class="d-tools-item">
                <FlashLight />
              </span>
              <span @click="handleRunItem(item, i)" class="d-tools-item" title="执行">
                <ExecuteRoundIcon class="d-list-item-icon" title="执行" />
              </span>
              <span class="d-tools-item">
                <div class="d-dropdown d-drop-hover d-drop-right">
                  <MenuIcon title="更多" />
                  <div class="d-list-menu d-list-cascade d-list-cascade-right">
                    <ul class="d-list-menu-group">
                      <li class="d-list-menu-item d-list-menu-item-setting">
                        <a @click="handleRunItem(item, i)" class="d-list-item-row">
                          <ExecuteRoundIcon class="d-list-item-icon" title="执行" />
                          <span class="d-list-item-text">执行</span>
                        </a>
                      </li>
                      <li class="d-list-menu-item d-list-menu-item-setting">
                        <a @click="handleEditItem(item)" class="d-list-item-row">
                          <EditIcon class="d-list-item-icon" title="编辑" />
                          <span class="d-list-item-text">编辑</span>
                        </a>
                      </li>
                      <li class="d-list-menu-item d-list-menu-item-setting">
                        <a :href="'#process/execute/design/' + item.eid" target="_blank" class="d-list-item-row">
                          <ListStyleIcon class="d-list-item-icon" title="流程线" />
                          <span class="d-list-item-text">流程线</span>
                        </a>
                      </li>
                      <li v-if="!isView" class="d-list-menu-item d-list-menu-item-del">
                        <a @click="handleRemoveDesign(item)" class="d-list-item-row">
                          <DeleteIcon class="d-list-item-icon" title="删除" />
                          <span class="d-list-item-text">删除</span>
                        </a>
                      </li>
                    </ul>
                  </div>
                </div>
              </span>
            </div>
          </div>
        </div>
        <div class="d-paner-body">
          <Executor :execute="item" :mode="'view'" ref="executorView" />
        </div>
      </div>
    </div>
    <Dialoger v-model="isShowDesign" :onConfirm="handleSubmitDesign" :dialogCls="'d-paner-lg'" title="编辑">
      <template v-slot:body>
        <Executors ref="designView" />
      </template>
    </Dialoger>
    <Dialoger v-model="isShowExeSetting" :onConfirm="handleSubmitExeSetting" :dialogCls="'d-paner-lg'" title="设置">
      <template v-slot:body>
        <ExeSetting :config="state.data.config" ref="exeSettingView" />
      </template>
    </Dialoger>
    <Dialoger v-model="isShowExeEdit" :onConfirm="handleSubmitExeEdit" :dialogCls="'d-paner-lg'" title="流程线编辑">
      <template v-slot:body>
        <ExeEdit :data="currentEditExe" ref="exeEditView" />
      </template>
    </Dialoger>
  </div>
</template>

<script>
import { PanerForm } from '@daelui/vdog/dist/pages.js'
import { Dialoger, FormCalendar, FormSelecter, Switcher, Tabs, TabsItem } from '@daelui/vdog/dist/components.js'
import {
  ReturnIcon, SettingIcon,
  EditIcon, CopyIcon, DeleteIcon, FullScreenIcon, ResetIcon,
  RestoreScreenIcon, RefreshIcon, WindowsIcon,
  MenuIcon, ListStyleIcon, ArrowLeftIcon, PreviewIcon,
  ToDownIcon, PlusRoundIcon, PowerIcon, PlusIcon, ExecuteRoundIcon
} from '@daelui/vdog/dist/icons.js'
import Executors from './executors.vue'
import ExeSetting from './exe-setting.vue'
import ExeEdit from './exe-edit.vue'
import groupSer from '../../../service/action/exegroup.action'
import cuteSer from '../../../service/action/execute.action'
import { state } from '../../../service/stock/index.js'
import { zh as locale } from '@daelui/dogjs/dist/locale.js'
import { objecter, arrayer, parser, strer } from '@daelui/dogjs/dist/components.js'
import storeMan from '../../../components/store-man'
import Executor from '../execute/executor.vue'
import FlashLight from '../../../components/flash-light'

export default {
  components: {
    PanerForm,
    SettingIcon,
    ReturnIcon,
    EditIcon,
    CopyIcon,
    DeleteIcon,
    FullScreenIcon,
    RestoreScreenIcon,
    RefreshIcon,
    WindowsIcon,
    MenuIcon,
    ListStyleIcon,
    ArrowLeftIcon,
    ToDownIcon,
    PlusRoundIcon,
    PreviewIcon,
    PowerIcon,
    PlusIcon,
    ExecuteRoundIcon,
    ResetIcon,
    Switcher,
    Tabs,
    TabsItem,
    FormSelecter,
    FormCalendar,
    Dialoger,
    Executors,
    Executor,
    ExeSetting,
    ExeEdit,
    FlashLight
  },

  data () {
    return {
      // 是否是视图模式
      isView: false,
      // 表单数据
      state: {
        id: '',
        name: '',
        productId: '',
        type: '',
        data: {nodes: [], config: {}},
        description: '',
        status: 1,
        order: 1,
        updateTime: '',
        updateUser: '',
        createTime: '',
        createUser: ''
      },
      exeList: [],
      // 流程单元列表
      units: [],
      // 单元列表
      unitList: [],
      // 状态列表
      statusList: state.statusList,
      // 是否周期
      isCycle: false,
      // 过滤关键字
      matchKeyword: '',
      // 是否显示编辑
      isShowDesign: false,
      isShowExeSetting: false,
      // 缓存数据
      cacheData: {},
      // 是否显示编辑流程线
      isShowExeEdit: false,
      // 当前编辑的流程线
      currentEditExe: {}
    }
  },

  computed: {
    // 流程数组
    executeList () {
      let nodes = this.state.data.nodes || []
      let exeList = this.exeList
      nodes = nodes.map(node => {
        let item = exeList.find(exe => {
          return exe.id === node.executeId
        })
        item = item || {}
        node.config = Object.assign({
          name: item.name || '',
          order: item.order || 1
        }, node.config || {})
        item = Object.assign(
          {}, item,
          {id: node.id, config: node.config || {}, eid: item.id},
          {name: node.config.name, order: node.config.order}
        )
        item.node = node
        return item
      }).sort(function (a, b) {
        return arrayer.sort(a.order, b.order, 'desc', false)
      })
      this.initExelineCycle()
      return nodes
    }
  },

  methods: {
    /**
     * @function 加载数据
    */
    loadItem (id) {
      return groupSer.queryItem({ id }).then(result => {
        let data = result.data || {}
        data.data = parser.parse(data.data, 'object', true)
        let nodes = (data.data || {}).nodes
        nodes = Array.isArray(nodes) ? nodes : []
        nodes.forEach(item => {
          item.status = ''
        })
        data.data.nodes = nodes
        let config = data.data.config
        config = config || {}
        data.data.config = config
        this.state = data
      })
    },

    /**
     * @function 执行
    */
    handleRunAll () {
      let defer = Promise.resolve({})
      this.executeList.forEach((item, i) => {
        defer = defer.then(this.$refs.executorView[i].handleRun())
      })
    },

    /**
     * @function 重置
    */
    handleResetAll () {
      this.executeList.forEach((item, i) => {
        this.$refs.executorView[i].handleReset()
      })
    },

    /**
     * @function 执行
    */
    handleCycleAll () {
      let defer = Promise.resolve({})
      this.executeList.forEach((item, i) => {
        item.config = item.config || {}
        if (item.config.isCycle !== true) {
          defer = defer.then(this.$refs.executorView[i].handleRun())
        }
      })
    },

    /**
     * @function 执行
    */
    handleRunItem (item, i) {
      this.$refs.executorView[i].handleRun()
    },

    /**
     * @function 获取单元
    */
    handleAddNode () {
      this.isShowDesign = true
    },

    /**
     * @function 编辑
    */
    handleEdit () {},

    /**
     * @funcition 刷新
    */
    handleRefresh () {
      this.initView()
    },

    /**
     * @funcition 添加流程节点
    */
    handleBack () {
      this.$router.push(this.getMicroRoute('/process/exegroup/list'))
    },

    /**
     * @funcition 添加流程节点
    */
    handleSubmitDesign () {
      let view = this.$refs.designView
      let executeId = view.executeId
      if (!executeId) {
        Dialoger.warn('未选择流程')
        return false
      }
      // 添加节点
      this.state.data.nodes.push({
        id: strer.utid(),
        executeId,
        config: {}
      })
    },

    handleEditItem (item) {
      this.isShowExeEdit = true
      this.currentEditExe = item.node
    },

    handleSubmitExeEdit () {
      let config = this.$refs.exeEditView.getValue()
      this.currentEditExe.config = Object.assign(this.currentEditExe.config || {}, config || {})
      let n = this.state.data.nodes.findIndex(item => item === this.currentEditExe)
      if (n > -1) {
        let item = this.state.data.nodes[n]
        this.$set(this.state.data.nodes, n, item)
      }
      this.initExelineCycle()
    },

    /**
     * @funcition 初始化流程线周期执行
    */
    initExelineCycle () {
      // 清除存在的循环
      this.timerList = Array.isArray(this.timerList) ? this.timerList : []
      this.timerList.forEach(item => {
        clearTimeout(item)
      })
      // 取出设置循环的流程线
      let nodes = (this.state.data || {}).nodes
      nodes = Array.isArray(nodes) ? nodes : []
      nodes = nodes.filter((item, i) => {
        item.config = item.config || {}
        return item.config.isCycle === true
      })
      // 执行
      const invoke = (timeout, i) => {
        let timer = setTimeout(() => {
          Promise.resolve(this.$refs.executorView[i].handleRun()).then(() => {
            invoke(timeout, i)
          })
        }, timeout * 1000)
        this.timerList[i] = timer
      }
      // 开始循环
      nodes.forEach((item, i) => {
        let timeout = parseInt(item.config.cycleTime)
        timeout = isNaN(timeout) ? 300 : timeout
        timeout = timeout < 1 ? 1 : timeout
        invoke(timeout, i)
      })
    },

    /**
     * @funcition 删除流程节点
    */
    handleRemoveDesign (node) {
      Dialoger.confirm(locale.message.confirmDelete).then(b => {
        if (!b) {
          return false
        }
        this.state.data.nodes = this.state.data.nodes.filter(item => {
          return item.id !== node.id
        })
        this.initExelineCycle()
      })
    },

    /**
     * @funcition 保存
    */
    handleSubmitSave () {
      let state = objecter.clone(this.state, {
        callProperty (val, i) {
          if (val && val.$set) {
            return false
          }
          if (i === 'stepStatus') {
            return false
          }
        }
      })
      state.data = parser.stringify(state.data)
      groupSer.editItem(state).then(result => {
        if (result.success) {
          Dialoger.success(locale.action.success)
        } else {
          Dialoger.danger(locale.action.fail)
        }
      })
    },

    /**
     * @funcition 初始化
    */
    initView () {
      let params = this.$route.params
      // 预览模式
      if (/view/.test(this.$route.path)) {
        this.isView = true
      }
      // 查询流程列表
      cuteSer.queryAll().then(list => {
        this.exeList = list
        // 查询单元列表
        this.loadItem(params.id).then(() => {
          // 缓存
          storeMan.getItem('group-cycle-' + params.id).then(cacheConfig => {
            cacheConfig = parser.parse(cacheConfig, 'object', true, {})
            this.cacheData = cacheConfig
            let config = Object.assign({}, (this.state.data || {}).config || {}, this.cacheData || {})
            let isCycle = false
            if (String(config.isCycle) === '1' || String(config.isCycle) === 'true') {
              isCycle = true
              this.stopTimer()
              this.runCycle()
            }
            this.isCycle = isCycle
          })
        })
      })
    },

    /**
     * @function 设置组
    */
    handleSettingExe () {
      this.isShowExeSetting = true
    },

    /**
     * @function 保存组设置
    */
    handleSubmitExeSetting () {
      let config = this.$refs.exeSettingView.getValue()
      this.state.data.config = config
      // 周期执行
      this.handleCycle()
    },

    /**
     * @function 切换周期执行
    */
    handleCycle () {
      this.stopTimer()
      let config = (this.state.data || {}).config || {}
      this.cacheData = Object.assign(this.cacheData, config)
      config = Object.assign({}, config, this.cacheData || {})
      storeMan.setItem('group-cycle-' + this.state.id, parser.stringify(this.cacheData), {cache: true})
      let isCycle = false
      if (String(config.isCycle) === '1' || String(config.isCycle) === 'true') {
        isCycle = true
        this.runCycle()
      } else {
        this.stopCycle()
      }
      this.isCycle = isCycle
    },

    /**
     * @function 执行周期
    */
    runTimeout () {
      clearTimeout(this.timer)
      // 周期时间秒数
      let config = Object.assign({}, (this.state.data || {}).config || {}, this.cacheData || {})
      let time = config.cycleTime
      time = parseInt(time)
      time = isNaN(time) ? 5 * 60 : time
      time = time * 1000
      this.timer = setTimeout(() => {
        this.handleCycleAll()
      }, time)
    },

    /**
     * @function 切换周期执行
    */
    switchCycle (val) {
      if (val) {
        this.runCycle()
      } else {
        this.stopCycle()
      }
    },

    /**
     * @function 周期执行
    */
    runCycle () {
      clearTimeout(this.timer)
      this.runTimeout()
    },

    /**
     * @function 停止周期执行
    */
    stopCycle () {
      clearTimeout(this.timer)
    },

    stopTimer () {
      clearTimeout(this.timer)
    }
  },

  beforeMount () {
    // 初始视图
    this.initView()
  },

  beforeDestroy () {
    this.stopTimer()
  }
}
</script>

<style lang="less" scoped>
.layout-full {
  flex: 1;
  width: 100%;
  height: 100%;
}
.d-bar {
  padding-left: 8px;
  padding-right: 8px;
  .d-bar-item-btns {
    font-size: 18px;
  }
  .d-bar-item {
    margin: 0;
  }
  .d-bar-item:first-child {
    flex-basis: 50%;
  }
  & + .pages {
    height: calc(~"100% - 38px");
  }
}
.d-list-item-icon {
  color: #999;
}
.item-text {
  overflow: hidden;
  max-width: 120px;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.icon-return {
  display: flex;
  align-items: center;
  font-size: 20px;
  color: #999;
  cursor: pointer;
}
.pages {
  flex: 1;
  height: 100%;
  .d-paner-body {
    overflow: hidden;
  }
}
.pages-item {
  margin-top: 8px;
  .d-paner-body {
    min-height: 120px;
  }
}
.header-content {
  display: flex;
  width: 100%;
}
.d-bar-tools {
  overflow: visible;
  padding: 0;
}
.d-item-link {
  .d-icon-svg, .item-link-text {
    vertical-align: middle;
  }
  .item-link-text {
    margin-left: 8px;
  }
}
.d-paner-fullscreen {
  border: none;
  .d-paner-header {
    position: relative;
    padding: 0;
    height: 0;
    border: none;
  }
  .header-content {
    position: absolute;
    display: flex;
    overflow: visible;
    top: 0;
    height: 0;
    width: 100%;
  }
  .d-paner-caption {
    overflow: hidden;
    visibility: hidden;
    height: 0;
  }
  .d-bar-tools {
    padding-right: 4px;
    height: 24px;
    opacity: 0.2;
    &:hover {
      opacity: 0.8;
    }
    .d-item-switch {
      display: none;
    }
    .item-full {
      display: block;
    }
    .d-hidden {
      display: inline;
    }
    .d-list-menu-item-setting,
    .d-list-menu-item-del {
      display: none;
    }
  }
}
.menu-group-sm .d-icon-svg {
  font-size: 16px;
}
.rotate {
  transform: rotate(180deg)
}
.group-menu {
  max-height: 274px;
  overflow: auto;
}
</style>

<style lang="less">
.d-contenter-tab.d-contenter {
  padding: 0;
  .pages-tab-full {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 5;
  }
  .d-bar {
    margin-left: 0;
    margin-right: 0;
  }
  .d-tabs {
    display: flex;
    height: 100%;
    flex-direction: column;
  }
  .d-tabs-paner {
    flex: 1;
  }
  .d-paner-list,.d-paner-item {
    height: 100%;
  }
  .tabs-nav-tail {
    justify-content: flex-end;
    position: relative;
    width: 150px;
    border: none;
    &:after {
      content: "";
      position: absolute;
      left: 0;
      bottom: 0;
      width: 100%;
      height: 1px;
      background-color: #e4e7ed;
      z-index: 1;
    }
    .d-bar-item-btns {
      justify-content: flex-end;
      flex-basis: 100%;
      font-size: 20px;
    }
    .d-item-switch {
      display: flex;
      align-items: center;
    }
    .d-switch-slider {
      font-size: 14px;
    }
    .d-dropdown {
      height: 20px;
      & > .d-icon-svg {
        vertical-align: top;
      }
    }
    .d-bar-item,.d-bar-text {
      overflow: visible;
    }
    .d-list-item-text {
      font-size: 14px;
      font-weight: 400;
    }
  }
  .item-is-active {
    &:after {
      content: "";
      position: absolute;
      top: 50%;
      right: 4px;
      margin-top: -4px;
      width: 8px;
      height: 8px;
      border-radius: 50%;
      background: #69C13D;
    }
  }
}
</style>
